#include <iostream>

class Base
{
public:
	Base()
	{
		std::cout << "[Base::" << __FUNCTION__ << ":" << __LINE__ << ": constructor]" << std::endl;
	}
	
    virtual ~Base()
	{
		std::cout << "[Base::" << __FUNCTION__ << ":" << __LINE__ << ": destructor]" << std::endl;
	}

	virtual void f(float x)
	{
		std::cout << "[Base::" << __FUNCTION__ << ":" << __LINE__ << "] " << x << std::endl;
	}

	void g(float x)
	{
		std::cout << "[Base::" << __FUNCTION__ << ":" << __LINE__ << "] " << x << std::endl;
	}

	void h(float x)
	{
		std::cout << "[Base::" << __FUNCTION__ << ":" << __LINE__ << "] " << x << std::endl;
	}
};


class Derived : public Base
{
public:
	Derived()
	{
		std::cout << "[Derived::" << __FUNCTION__ << ":" << __LINE__ << ": constructor]" << std::endl;
	}

	~Derived()
	{
		std::cout << "[Derived::" << __FUNCTION__ << ":" << __LINE__ << ": destructor]" << std::endl;
	}

    void f(float x)
	{
		std::cout << "[Derived::" << __FUNCTION__ << ":" << __LINE__ << "] " << x << std::endl;
	}

	void g(int x)
	{
		std::cout << "[Derived::" << __FUNCTION__ << ":" << __LINE__ << "] " << x << std::endl;
	}

	void h(float x)
	{
		std::cout << "[Derived::" << __FUNCTION__ << ":" << __LINE__ << "] " << x << std::endl;
	}
};


/*
“隐藏”是指派生类的函数屏蔽了与其同名的基类函数，规则如下：
（1）如果派生类的函数与基类的函数同名，但是参数不同。此时，不论有无virtual关键字，基类的函数将被隐藏（注意别与重载混淆）。
（2）如果派生类的函数与基类的函数同名，并且参数也相同，但是基类函数没有virtual关键字。此时，基类的函数被隐藏（注意别与覆盖混淆）。
上面的程序中：
（1）函数Derived::f(float)覆盖了Base::f(float)。
（2）函数Derived::g(int)隐藏了Base::g(float)，而不是重载。
（3）函数Derived::h(float)隐藏了Base::h(float)，而不是覆盖。
*/
void TestForDerived()
{
#define TEST (0)

#if defined(TEST) && (TEST != 0)
	Derived* d = new Derived();
	if (!d)
	{
		std::cout << "[" << __FUNCTION__ << ":" << __LINE__ << "] new Derived failed" << std::endl;
		return -1;
	}

	Base* pb = d;
	Derived* pd = d;
#else
	Derived d;
	Base* pb = &d;
	Derived* pd = &d;
#endif

	// 派生类函数名和参数与基类一致，且派生类的函数前面有关键字virtual，这时基类的函数会被覆盖
	pb->f(3.14f); // 调用的是子类的f方法
	pb->g(3.14f);
	pb->h(3.14f);

	pd->f(3.14f);
	pd->g(3.14f);
	pd->h(3.14f);

#if defined(TEST) && (TEST != 0)
	if (d)
	{
        delete d;
    	d = NULL;
    }
#endif
}


int main(int argc, char* argv[])
{
	TestForDerived();
	return 0;
}
